package com.hbase.tools;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.Connection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/*
 * 1.创建/删除/查询/判断是否存在  名称空间
 *
 * 		hbase shell	:	开启一个客户端对象
 *      hbase shell	:	create_namespace 库名
 *
 * 2.Admin	:	提供对hbase管理的一些api
 * 		例如创建，删除，查询表等
 * 		可以使用Connection.getAdmin()来获取Admin的一个实例，使用完成后，调用close关闭
 *
 * 3.Connection	:	Connection代表客户端和集群的一个连接！这个连接包含对master的连接，和zk的连接！
 * 					Connection可以使用ConnectionFactory来创建！
 * 					Connection的创建是重量级的，因此建议一个应用只创建一个Connection对象！
 * 					Connection是线程安全的，可以在多个线程中共享同一个Connection实例！
 * 					Connection的生命周期也是用户自己控制！
 *
 * 					从Connection中获取Table和Admin对象的实例！
 * 					Table和Admin对象的创建是轻量级的，且不是线程安全的！
 * 					因此不建议池化或缓存Table和Admin对象实例，每个线程有自己的Table和Admin对象的实例！
 *
 * 4.NamespaceDescriptor	:	用来代表和定义名称空间
 */

public class NameSpaceUtil {

	// 用来记录一些信息
	private static Logger logger = LoggerFactory.getLogger(NameSpaceUtil.class);

	// 查询所有的名称空间
	public static List<String> listNameSpace(Connection conn) throws IOException {

		ArrayList<String> nss = new ArrayList<>();

		// 提供一个Admin
		Admin admin = conn.getAdmin();

		// 查询所有的库
		NamespaceDescriptor[] namespaceDescriptors = admin.listNamespaceDescriptors();

		for (NamespaceDescriptor namespaceDescriptor : namespaceDescriptors) {

			// 取出每个库描述中库的名称
			nss.add(namespaceDescriptor.getName());

		}

		// 关闭Admin
		admin.close();

		return nss;

	}

	// 判断库是否存在
	public static boolean ifNSExists(Connection conn, String nsname) throws IOException {

		// 库名的校验
		if (StringUtils.isBlank(nsname)) {

			logger.error("请输入正确的库名！");
			// 在后台提示库名非法
			return false;

		}

		// 提供一个Admin
		Admin admin = conn.getAdmin();

		// 根据库名查询对应的NS，如果找不到就抛异常
		try {

			admin.getNamespaceDescriptor(nsname);

			return true;

		} catch (Exception e) {

//			e.printStackTrace();

			return false;

		} finally {

			// 关闭Admin
			admin.close();

		}

	}

	// 创建库
	public static boolean createNS(Connection conn, String nsname) throws IOException {

		// 库名的校验
		if (StringUtils.isBlank(nsname)) {

			logger.error("请输入正确的库名！");
			// 在后台提示库名非法
			return false;

		}

		// 提供一个Admin
		Admin admin = conn.getAdmin();

		// 新建库
		try {

			// 先创建库的定义
			NamespaceDescriptor descriptor = NamespaceDescriptor.create(nsname).build();

			admin.createNamespace(descriptor);

			return true;

		} catch (Exception e) {

//			e.printStackTrace();

			return false;

		} finally {

			// 关闭Admin
			admin.close();

		}

	}

	// 删除库
	public static boolean deleteNS(Connection conn, String nsname) throws IOException {

		// 先判断库是否存在
		if(ifNSExists(conn, nsname) == false) {
			logger.error("库不存在！");
			return false;
		}

		// 提供一个Admin
		Admin admin = conn.getAdmin();

		// 删除库
		// 只能删除空库，判断当前库是否为empty，不为空无法删除
		// 查询当前库下有哪些表
		List<String> tables = getTablesInNameSpace(conn, nsname);

		if(tables.size() == 0) {

			admin.deleteNamespace(nsname);
			// 关闭Admin
			admin.close();

			return true;

		} else {

			// 关闭Admin
			admin.close();

			logger.error("库非空，无法删除！");
			return false;

		}



	}

	// 查询当前库下有哪些表
	public static List<String> getTablesInNameSpace(Connection conn, String nsname) throws IOException {

		// 先判断库是否存在
		if (ifNSExists(conn, nsname) == false) {
			return null;
		}

		ArrayList<String> tables = new ArrayList<>();

		// 提供一个Admin
		Admin admin = conn.getAdmin();

		// 查询指定库下所有表
		HTableDescriptor[] tableDescriptors = admin.listTableDescriptorsByNamespace(nsname);

		for (HTableDescriptor tableDescriptor : tableDescriptors) {

			// 取出指定库中所有表
			tables.add(tableDescriptor.getNameAsString());

		}

		// 关闭Admin
		admin.close();

		return tables;

	}

}
